from decimal import Decimal

import logging
from django.db import transaction
from django.db.models import F
from django.utils import timezone
from django_redis import get_redis_connection
from rest_framework import serializers
from rest_framework.response import Response

from goods.models import SKU
from orders.models import OrderInfo, OrderGoods

logger = logging.getLogger('django')


class CartSKUSerializer(serializers.ModelSerializer):
    """购物车商品信息返回序列化器"""
    count = serializers.IntegerField(label='商品数量')

    class Meta:
        model = SKU
        fields = ('id', 'name', 'default_image_url', 'price', 'count')


class OrderSettleSerializer(serializers.Serializer):
    """订单数据序列化返回"""
    freight = serializers.DecimalField(label='运费', max_digits=10, decimal_places=2)
    skus = CartSKUSerializer(many=True)


class SaveOrderSerializer(serializers.ModelSerializer):
    """下单数据序列化器"""

    class Meta:
        # 进行序列化操作的时候将数据进行校验
        model = OrderInfo
        fields = ['address', 'pay_method', 'order_id']
        read_only_fields = ('order_id',)
        extra_kwargs = {
            "address": {
                'write_only': True,
                'required': True
            },
            'pay_method': {
                'required': True,
                'write_only': True
            }
        }

    def create(self, validated_data):
        """保存订单到数据库"""
        # 1.获取用户
        user = self.context['request'].user
        # 2.生成订单id 使用django的timezone模块 生成日期时间格式字符串
        # 拼接日期时间字符串和用户id的9位表示方式  000012345  作为订单编号
        order_id = timezone.now().strftime('%Y%m%d%H%M%S') + ('%09d' % user.id)
        address = validated_data['address']
        pay_method = validated_data['pay_method']
        # 3.从redis中查询勾选商品的数据信息
        redis_conn = get_redis_connection('cart')
        # 查询hash中的商品信息  {15:1,16:2}
        redis_cart = redis_conn.hgetall('carts_%s' % user.id)
        # 查询set中的勾选商品数据
        redis_selected = redis_conn.smembers('cart_selected_%s' % user.id)
        # 创建字典用以保存勾选的商品的信息
        cart = {}
        for sku_id in redis_selected:
            # cart[16]=1
            cart[int(sku_id)] = int(redis_cart[sku_id])
        if not cart:
            raise serializers.ValidationError('没有需要结算的商品')
        # 开启事务  保存订单
        with transaction.atomic():
            # 创建保存点
            saveid = transaction.savepoint()
            # 创建商品订单基本信息表
            try:
                order = OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address=address,
                    pay_method=pay_method,
                    total_count=0,
                    total_amount=Decimal(0),
                    freight=Decimal(10),
                    status=OrderInfo.ORDER_STATUS_ENUM['UNSEND'] if pay_method == OrderInfo.PAY_METHODS_ENUM[
                        'CASH'] else
                    OrderInfo.ORDER_STATUS_ENUM['UNPAID']
                )

                # 一次查询出所有商品数据
                # skus = SKU.objects.filter(id__in=cart.keys())
                sku_id_list = cart.keys()

                # 遍历订单商品列表,处理订单商品
                for sku_id in sku_id_list:
                    # 在每次进循环时查询订单商品
                    sku = SKU.objects.get(id=sku_id)
                    # 订单商品的数量
                    sku_count = cart[sku.id]
                    import time
                    time.sleep(5)
                    # 在商品列表中的原始库存 以及销量
                    # origin_stock = sku.stock
                    # origin_sales = sku.sales

                    # # 如果订单商品数量大于库存 抛出异常
                    # if sku_count > origin_stock:
                    #     # 回滚到保存点
                    #     transaction.savepoint_rollback(saveid)
                    #     raise serializers.ValidationError('%s库存不足' % sku.id)
                    # 更新库存
                    # new_stock = origin_stock - sku_count
                    # new_sales = origin_sales + sku_count
                    # 查询和更新放到一起
                    result = SKU.objects.filter(id=sku.id, stock__gte=sku_count).update(stock=F("stock") - sku_count,
                                                                                        sales=F("sales") + sku_count)
                    # result返回受影响的行数
                    if result == 0:
                        raise serializers.ValidationError('%s商品库存不足' % sku.name)

                    # 订单表的数量和金额需要随之改变
                    order.total_count += sku_count
                    order.total_amount += sku_count * sku.price

                    # 创建订单商品
                    OrderGoods.objects.create(
                        order=order,
                        sku=sku,
                        price=sku.price,
                        count=sku_count
                    )
                    # 循环结束说明所有订单商品都已添加到表中,此时需要更新order表
                order.total_amount += order.freight
                order.save()
            except serializers.ValidationError:
                raise
            except Exception as e:
                logger.error(e)
                # 回滚事务
                transaction.savepoint_rollback(saveid)
                raise
            else:  # 提交事务
                transaction.savepoint_commit(saveid)

        # 删除redis中选中的商品数据
        pl = redis_conn.pipeline()
        pl.hdel('carts_%s' % user.id, *redis_selected)
        pl.srem('cart_selected_%s' % user.id, *redis_selected)
        pl.execute()

        return order
